home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Ken Long / MissileCmd2.3-p-c / Missile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-04  |  33.4 KB  |  1,326 lines  |  [TEXT/MMCC]

  1. #pragma mark Includes<I
  2. //•    ------------------------------    Includes
  3.  
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6.  
  7. #pragma mark Prototypes<I
  8. //•    ------------------------------    Prototypes
  9.  
  10. void        SetupMenus (void);
  11. void        InitFireballs (void);
  12. void        SetupEverything (void);
  13. short        MunafoRandom (short n);
  14. void        DrawANumber (long n);
  15. void        UpdateScore (void);
  16. void        DrawTheScore (void);
  17. void        DrawBottomLine (void);
  18. void        AllocateFireballs (Point location);
  19. void        AdvanceFireballs (void);
  20. void        AllocateMissiles (Point position, short city, short kind);
  21. Boolean    BlackPixel (Point aPoint);
  22. void        AdvanMS (void);
  23. void        CenterSomeText (Str255 TheText, short posV);
  24. void        ClearTheScreen (void);
  25. void        DrawACity (short city);
  26. void        DrawOurStuff (void);
  27. short    NumStrMinMax (Str255 theString, short minimum, short MAXIMUM);
  28. void        DoGameOptions (void);
  29. void        DoCommand (long whichMenu);
  30. void        CheckEvents (void);
  31. void        GameOverScreen (void);
  32. void        InitializeRound (void);
  33. void        EndRoundBonus (void);
  34. void        PlayMacMissile (void);
  35. void        main (void);
  36. void        SetPString (Str255 thePString, char *theCString);
  37.  
  38. #pragma mark Constants<I
  39. //•    ------------------------------    Private Constants
  40.  
  41. #define FP_SHIFT        4                        //•    Number of positions to shift for Fixed-Point math
  42.  
  43. #define rsrcMainMBAR    128                        //•    resource ID of our MBAR definition
  44.  
  45. #define appleMenu        128                        //•    menu ID for desk accessory menu.
  46. #define    iAbout        1
  47.  
  48. #define fileMenu        129                        //•    menu ID for File menu.
  49. #define    iQuit            1
  50.  
  51. #define gameMenu        131                        //•    menu ID for Game menu.
  52. #define    iPause        1
  53. #define    iResume        2
  54.         //-------------
  55. #define    iOptions        4
  56. #define    iNewGame        5
  57.  
  58. #define aboutAlert        128            //•    ID of "about" alert box.
  59. #define optionsDialog    129            //•    ID of options box.
  60.  
  61. #define fbIdle            0
  62. #define fbGrow            1
  63. #define fbShrink        2
  64. #define maxFB            60            //•    Maximum number of fireballs allowed.
  65. #define fbRad            15            //•    Radius of fireballs.
  66. #define fbRadRate        2            //•    Rate of expansion/contraction of fireballs.
  67. #define msIdle            0
  68. #define msActive        1
  69. #define msNormal        1
  70. #define msMIRV            2
  71. #define msSmart            3
  72. #define maxMS            20            //•    Maximum number of missiles allowed.
  73. #define mWidth            3            //•    Width of missile tracks.
  74. #define cityHeight        40            //•    Distance from bottom up to cities.
  75. #define cityWidth        50            //•    Width of cities.
  76. #define buildHeight        30            //•    Maximum height of buildings.
  77. #define buildWidth        4            //•    Width of buildings.
  78. #define numCities        6            //•    Number of cities.
  79.  
  80. #pragma mark Definitions<I
  81. //•    ------------------------------    Private Definitions
  82.  
  83. typedef struct                        //•    Data type to describe a fireball.
  84. {
  85.     Rect bounds;                    //•    Rectanggle to copy bits into.
  86.     short size;                        //•    Current radius of fireball.
  87.     short mode;                        //•    Idle, Growing, or shrinking.
  88. } fireball;
  89.  
  90. typedef struct                        //•    Data type to describe a missile.
  91. {
  92.     Point start;                    //•    One endpoint of the missile's path.
  93.     Point pos;                        //•    Position within path - 0 to 1.
  94.     short dh, dv;                    //•    Vertical and horizontal speed in pixels.
  95.     short city;                        //•    Number of the target city.
  96.     short kind;                        //•    MIRV or normal.
  97.     short mode;                        //•    Idle or Active.
  98. } missile;
  99.  
  100. #pragma mark Globals<I
  101. //•    ------------------------------    Private Variables
  102.  
  103. Rect            screenRect;
  104. Boolean        doneFlag;
  105. EventRecord    myEvent;
  106. short        code, refNum;
  107. WindowPtr    myWindow, whichWindow;
  108.  
  109. BitMap        fbBitMap;                //•    BitMap for fireball pictures.
  110. short        fbBits[3601];            //•    Actual bits for fireball pictures.
  111.  
  112. Boolean        roundOver = FALSE;        //•    Current round is over.
  113. CursHandle    crosshair, crosshair2;    //•    Handle to the cursor.
  114. PatHandle    cityPattern;            //•    Handle to pattern in which to draw cities.
  115. short        fieldWidth;                //•    Width of the playing field.
  116. short        fieldHeight;            //•    Height of the playing field.
  117. short        i;                        //•    Loop variable.
  118. fireball    fbs[maxFB + 1];            //•    Each entry describes one fireball.
  119. missile        missiles[maxMS];        //•    Each entry describes one missile.
  120. short        nMissiles;                //•    Number of currently active missiles.
  121. long        lastTick;                //•    System clock at time of previous update.
  122. Boolean        gameOver;                //•    Set true when all cities are destroyed.
  123. Boolean        pauseFlag;                //•    True when game is being paused.
  124. Boolean        playing;                //•    True except buring bonus points and GAME OVER screens.
  125. Boolean        esFlag;                    //•    True if "GAME OVER" is to be drawn after exiting main loop.
  126. short        endDelay;                //•    Used to wait a while after end of round.
  127. short        citiesLeft;                //•    Number of cities still alive.
  128. short        bonusCities;            //•    Number of bonus cities they have left.
  129. Boolean     cities[numCities];        //•    State of each city : false = destroyed.
  130. Boolean        cities2[numCities];        //•    State of the city before the round began.
  131. short        nukeHeight;                //•    Vertical position of fireball required to destroy city.
  132. short        endv;                    //•    Y-coordinate of the end of a missile's path.
  133. short        MIRV_Rate;
  134. short        MIRV_Height;            //•    Height at which MIRVs MIRV.
  135. short        MIRV_Nasty;                //•    Percent chance of sub-missile on MIRV for each city.
  136. short        msSpeed;                //•    Vertical speed of missiles, in 1/16ths of a pixel..
  137. short        msRate;                    //•    Percent rate of missile production.
  138. short        roundNumber;            //•    Number of the current round.
  139. long        Score;                    //•    The player's current score.
  140. long        disScore;                //•    Score currently displayed on the screen.
  141. long        highScore;                //•    The current highest score.
  142. short        roundH;
  143. short        scoreH;                    //•    Horiz. position of text 'Score:.
  144. short        scoreNumH;                //•    Horiz. position of score.
  145. short        statsH;                    //•    Horiz. position of text 'Enemy left:.
  146. short        statsNumH;
  147. Rect        statsRect;
  148. short        eLeft;                    //•    How many enemy missiles are left this round.
  149. short        yLeft;                    //•    How many missiles you (the player) have left.
  150. short        eDestroyed;                //•    Number of enemy missiles destroyed.
  151. short        eDesH;                    //•    Horiz. position of text 'Enemy Destroyed:.
  152. short        eDesNumH;                //•    Horiz. position of # of enemy missiles destroyed.
  153. short        gameSpeed;                //•    Number of ticks between each Advance_Fireballs call.
  154. short        startRound;                //•    Round to start off with.
  155. Boolean        mFlag1;                    //•    Do missiles aim for dead cities?.
  156. short        mFlag2;                    //•    Extent to which enemy missiles blow up.
  157. Boolean        mExists[4];                //•    Does this type of missile occur?.
  158. short         mpBase[4];                //•    Value of missile at first round...
  159. short         mpExtra[4];                //•    ...plus this much each additional round...
  160. short        MPoints[4];                //•    ...is this much in all.
  161.  
  162. //•    ------------------------------    SetupMenus
  163.  
  164. void SetupMenus ()
  165. {
  166. Handle        theMenuBar;
  167. MenuHandle    tempMenu;
  168.     
  169.     //•    Load the menu bar
  170.     theMenuBar = GetNewMBar (rsrcMainMBAR);
  171.  
  172.     //•    Install the menu bar
  173.     SetMenuBar (theMenuBar);
  174.     DrawMenuBar ();
  175.  
  176.     //•    Add Apple Menu items
  177.     AddResMenu (GetMHandle (appleMenu), 'DRVR');
  178.     DisposeHandle (theMenuBar);
  179. }
  180.  
  181. //•    Init routine for fireball BitMaps..
  182. //•    This routine is called by the main Init routine, below.  It creates a
  183. //•    bunch of bit images of circles off-screen, which can later be drawn on
  184. //•    the screen much faster than FrameOval.
  185.  
  186. //•    ------------------------------    InitFireballs
  187.  
  188. void InitFireballs ()
  189. {
  190.     short    i;
  191.     Rect    aRect;        //•    Rectangle for drawing FrameOvals.
  192.     BitMap    saveBits;    //•    To save the current GrafPort while drawing off-screen.
  193.     Rect    saveRect;
  194.  
  195.     saveBits = qd.thePort->portBits;
  196.     saveRect = qd.thePort->portRect;
  197.     fbBitMap.rowBytes = 8;
  198.     SetRect (&fbBitMap.bounds, 0, 0, 60, 60);
  199.     qd.thePort->portRect = fbBitMap.bounds;
  200.  
  201.     PenSize (fbRadRate, fbRadRate);
  202.     PenPat (&qd.black);
  203.     PenMode (patCopy);
  204.  
  205.     //•    Start with an empty rectangle in the center.
  206.     SetRect (&aRect, 30, 30, 30, 30);
  207.     
  208.     for (i = 0; i < 14; i++) 
  209.     {
  210.         //•    Pick starting address for this picture.
  211.         fbBitMap.baseAddr =  (Ptr) &fbBits[240 * i + 1];
  212.  
  213.         //•    Make rect a bit larger.
  214.         InsetRect (&aRect, -2, -2);        
  215.         SetPortBits (&fbBitMap);
  216.         EraseRect (&qd.thePort->portBits.bounds);    //•    Erase to all white.
  217.         FrameOval (&aRect);                        //•    Draw the circle.
  218.     }
  219.     
  220.     SetPortBits (&saveBits);                    //•    Return to normal screen drawing.
  221.     qd.thePort->portRect = saveRect;
  222. }
  223.  
  224. //•    ------------------------------    SetupEverything
  225.  
  226. void SetupEverything ()
  227. {
  228. Rect        wRect;                                //•    Window Rectangle.
  229. short    i;
  230.  
  231.     MaxApplZone ();
  232.  
  233.     //•    Macintosh System initialization.
  234.     InitGraf (&qd.thePort);                        //•    Quickdraw.
  235.     InitFonts ();                                //•    Font Manager.
  236.     InitWindows ();                                //•    Window Manager.
  237.     InitMenus ();                                //•    Menu Manager.
  238.     TEInit ();                                    //•    TextEdit.
  239.     InitDialogs (0L);                                //•    Dialog manager.
  240.     InitCursor ();                                //•    Cursor handler.
  241.  
  242.     SetupMenus ();                                //•    My routine to insert the menus.
  243.     crosshair = GetCursor (256);                        //•    Load the Crosshairs cursor that I use in the game.
  244.     HLockHi ((Handle) crosshair);
  245.     SetCursor (*crosshair);
  246.     cityPattern = GetPattern (256);
  247.  
  248.     doneFlag = false;                            //•    This flag is set to False when user selects 'Quit'.
  249.     highScore = 0;
  250.  
  251.     gameSpeed = 8;                                //•    Set up all the user-settable options.
  252.     startRound = 0;
  253.     mFlag1 = true;
  254.     mFlag2 = 1;
  255.     
  256.     for (i = 0; i < 3; i++) 
  257.     {
  258.         mExists[i] = true;
  259.         mpBase[i] = 10 * i;
  260.         mpExtra[i] = 10 * i;
  261.     }
  262.  
  263.     //•    Might as well play the game in a window...
  264.     myWindow = GetNewWindow (128, nil,  (WindowPtr) -1L);
  265.     SetPort (myWindow);
  266.     ShowWindow (myWindow);
  267.  
  268.     //•    These variables are used by the game.
  269.     fieldWidth = myWindow->portRect.right;        
  270.     fieldHeight = myWindow->portRect.bottom;
  271.  
  272.     TextFont (0);
  273.     TextFace (0);
  274.  
  275.     InitFireballs ();                            //•    Set up the fireball BitMaps.
  276.  
  277.     FlushEvents (everyEvent, 0);
  278. }
  279.  
  280. //•    ------------------------------    ManufoRandom
  281.  
  282. short
  283. MunafoRandom (short n)
  284. {
  285. short    number;
  286.  
  287.     number =  abs (Random ()) % n;
  288.     return  (number);
  289. }
  290.  
  291. //•    ------------------------------    DrawANumber
  292.  
  293. void DrawANumber (long n)
  294. {
  295. Str255 s;
  296.  
  297.     NumToString (n, s);
  298.     DrawString (s);
  299. }
  300.  
  301. //•    ------------------------------    UpdateScore
  302.  
  303. void UpdateScore ()
  304. {
  305.     TextMode (srcBic);
  306.     MoveTo (scoreNumH, fieldHeight - 5);
  307.     TextSize (24);
  308.     DrawANumber (disScore);
  309.  
  310.     TextMode (srcOr);
  311.     MoveTo (scoreNumH, fieldHeight - 5);
  312.     DrawANumber (Score);
  313.     disScore = Score;
  314.  
  315.     EraseRect (&statsRect);
  316.     TextMode (srcOr);
  317.     MoveTo (statsNumH, fieldHeight - 20);
  318.     TextSize (12);
  319.     DrawANumber (eLeft);
  320.     MoveTo (statsNumH, fieldHeight - 5);
  321.     DrawANumber (yLeft);
  322.     TextMode (srcCopy);
  323.     MoveTo (eDesNumH, fieldHeight - 20);
  324.     DrawANumber (eDestroyed);
  325. }
  326.  
  327. //•    ------------------------------    DrawTheScore
  328.  
  329. void DrawTheScore ()
  330. {
  331.     TextMode (srcCopy);
  332.     MoveTo (scoreH, fieldHeight - 14);
  333.     TextSize (12);
  334.     DrawString ("\pScore: ");
  335.     MoveTo (scoreNumH, fieldHeight - 5);
  336.     TextSize (24);
  337.     DrawANumber (Score);
  338.     disScore = Score;
  339.  
  340.     TextSize (12);
  341.     MoveTo (statsH, fieldHeight - 20);
  342.     DrawString ("\pEnemy left: ");
  343.     DrawANumber (eLeft);
  344.  
  345.     MoveTo (statsH, fieldHeight - 5);
  346.     DrawString ("\pYours left: ");
  347.  
  348.     MoveTo (statsNumH, fieldHeight - 5);
  349.     DrawANumber (yLeft);
  350.  
  351.     MoveTo (eDesH, fieldHeight - 20);
  352.     DrawString ("\pDestroyed: ");
  353.  
  354.     MoveTo (eDesNumH, fieldHeight - 20);
  355.     DrawANumber (eDestroyed);
  356. }
  357.  
  358. //•    ------------------------------    DrawBottomLine
  359.  
  360. void DrawBottomLine ()
  361. {
  362.     TextSize (12);
  363.     roundH = 10 + StringWidth ("\pRound: ");
  364.     scoreH = roundH + 2 * StringWidth ("\p00 ");
  365.     scoreNumH = scoreH + StringWidth ("\pScore: ");
  366.     eDesH = fieldWidth - StringWidth ("\pDestroyed: 0000 ");
  367.     eDesNumH = fieldWidth - StringWidth ("\p0000 ");
  368.     statsH = eDesH - StringWidth ("\pEnemy left: 000  ");
  369.     statsNumH = eDesH - StringWidth ("\p000  ");
  370.  
  371.     SetRect (&statsRect, statsNumH, fieldHeight - 30, eDesH-2, fieldHeight);
  372.  
  373.     TextMode (srcCopy);
  374.     MoveTo (10, fieldHeight - 14);
  375.     DrawString ("\pRound: ");
  376.     MoveTo (roundH, fieldHeight - 5);
  377.     TextSize (24);
  378.     DrawANumber (roundNumber);
  379.  
  380.     DrawTheScore ();
  381.     MoveTo (eDesH, fieldHeight - 5);
  382.     DrawString ("\pHigh Score: ");
  383.     DrawANumber (highScore);
  384. }
  385.  
  386. //•    ------------------------------    AllocateFireballs
  387.  
  388. void AllocateFireballs (Point location)
  389. {
  390. short    i;
  391. short    idlefb;
  392.  
  393.     idlefb = 0;
  394.  
  395.     for (i = 0; i < maxFB; i++)
  396.         if  ((fbs[i].mode == fbIdle) &&  (idlefb == 0))
  397.             idlefb = i;
  398.  
  399.     if  (idlefb != 0) 
  400.     {
  401.         SetRect (&fbs[idlefb].bounds,    location.h - 30, 
  402.                                 location.v - 30, 
  403.                                 location.h + 30, 
  404.                                 location.v + 30);
  405.         fbs[idlefb].size = 0;
  406.         fbs[idlefb].mode = fbGrow;
  407.     }
  408. }
  409.  
  410. //•    ------------------------------    AdvanceFireballs
  411.  
  412. void AdvanceFireballs ()
  413. {
  414. short    i;
  415. Rect        aRect;
  416. Rect        fbRect;                                //•    Rectangle for drawing fireballs.
  417.  
  418.     PenSize (fbRadRate, fbRadRate);
  419.     PenPat (&qd.black);
  420.     SetRect (&aRect, 0, 0, 60, 60);
  421.     
  422.     for (i = 0; i < maxFB; i++) 
  423.     {
  424.         if  (fbs[i].mode != fbIdle)
  425.             switch (fbs[i].mode)
  426.             {
  427.                 case fbGrow: 
  428.                 {
  429.                     fbs[i].size = fbs[i].size + 1;
  430.                     fbBitMap.baseAddr =  (Ptr) &fbBits[240 * fbs[i].size - 239];    //•    Select a fireball picture.
  431.  
  432.                     CopyBits (&fbBitMap, &qd.thePort->portBits, &aRect, &fbs[i].bounds, srcOr, 0L);
  433.  
  434.                     if  (fbs[i].size >= fbRad)
  435.                         fbs[i].mode  = fbShrink;
  436.                 }
  437.                 break;
  438.  
  439.                 case fbShrink: 
  440.                 {
  441.                     fbBitMap.baseAddr =  (Ptr) &fbBits[240 * fbs[i].size - 239];    //•    Select the correct fireball picture.
  442.  
  443.                     CopyBits (&fbBitMap, &qd.thePort->portBits, &aRect, &fbs[i].bounds, srcBic, 0L);
  444.  
  445.                     fbs[i].size = fbs[i].size - 1;
  446.  
  447.                     if  (fbs[i].size == 0) 
  448.                         fbs[i].mode = fbIdle;
  449.                 }
  450.                 break;
  451.             }
  452.     }
  453. }
  454.  
  455. //•    ------------------------------    AllocateMissiles
  456.  
  457. void AllocateMissiles (Point position, short city, short kind)
  458. {
  459. short    i, idleMS, targetCity, target_H;
  460.  
  461.     for (i = 0, idleMS = 0; i < maxMS; i++)
  462.         if  (missiles[i].mode == msIdle && idleMS == 0) 
  463.             idleMS = i;
  464.  
  465.     if  (idleMS != 0)
  466.     {
  467.         i = idleMS;
  468.         
  469.         //•    Set coordinates for beginning of path.
  470.         missiles[i].start.v = position.v;        
  471.         missiles[i].start.h = position.h;
  472.  
  473.         //•    Initial current position is.
  474.         missiles[i].pos.v = missiles[i].start.v << FP_SHIFT;
  475.  
  476.         //•    at start of path.o.
  477.         missiles[i].pos.h = missiles[i].start.h << FP_SHIFT;
  478.  
  479.         //•    Speed of Missle
  480.         missiles[i].dv = msSpeed;                //•    Speed of missile.
  481.  
  482.         //•    Now that we know where we're going, calculate the horizontal delta necessary to get there in a vertical
  483.         //•    screen-full of iterations.
  484.         missiles[i].city = city + 1;
  485.         target_H =  (((missiles[i].city * 2 - 1) * fieldWidth) /  (numCities << 1)) << FP_SHIFT;
  486.  
  487.         missiles[i].dh =  (target_H -  (missiles[i].start.h << FP_SHIFT)) /  (((endv - missiles[i].start.v) << FP_SHIFT) / missiles[i].dv);
  488.         missiles[i].kind = kind;
  489.         missiles[i].mode = msActive;
  490.         nMissiles++;
  491.     }
  492. }
  493.  
  494.  
  495. //•    ------------------------------    BlackPixel
  496.  
  497. Boolean BlackPixel (Point aPoint)
  498. {
  499.     aPoint.h = aPoint.h >> FP_SHIFT;
  500.     aPoint.v = aPoint.v >> FP_SHIFT;
  501.     return  (GetPixel (aPoint.h, aPoint.v) && GetPixel (aPoint.h + 1, aPoint.v));
  502. }
  503.  
  504. //•    ------------------------------    AdvanMS
  505.  
  506. void AdvanMS ()
  507. {
  508.     short    i, j;
  509.     Point        newpos, newpixel;
  510.     Boolean    detonate;
  511.     short    points;
  512.  
  513.     PenMode (patCopy);
  514.  
  515.     for (i = 0; i < maxMS; i++) 
  516.     {
  517.         if  (missiles[i].mode != msIdle)
  518.         {
  519.             newpos.v = missiles[i].pos.v + missiles[i].dv;
  520.             newpos.h = missiles[i].pos.h + missiles[i].dh;
  521.             newpixel.v = newpos.v >> FP_SHIFT;
  522.             newpixel.h = newpos.h >> FP_SHIFT;
  523.  
  524.             detonate = false;
  525.             if  (BlackPixel (newpos) || BlackPixel (missiles[i].pos))
  526.                 detonate = true;
  527.  
  528.             PenSize (mWidth, mWidth);
  529.             PenPat (&qd.gray);
  530.             MoveTo (missiles[i].pos.h >> FP_SHIFT, missiles[i].pos.v >> FP_SHIFT);
  531.             LineTo (newpixel.h, newpixel.v);
  532.             missiles[i].pos = newpos;
  533.  
  534.             //•    If it's a MIRV, and it's reached the right altitude, 
  535.             if  ((missiles[i].kind == msMIRV)  &&  (newpixel.v > MIRV_Height))
  536.             {
  537.                 //•    then make lots of little missiles...
  538.                 for (j = 1; j < numCities; j++)
  539.                     if  ((j != missiles[i].city) &&  (MunafoRandom (100) < MIRV_Nasty)) 
  540.                         AllocateMissiles (newpixel, j, msNormal);
  541.  
  542.                 missiles[i].kind = msNormal;
  543.             }
  544.             
  545.             //•    If the missile has reached its target or hit a fireball...
  546.             if  ((newpos.v >> FP_SHIFT >= endv) || detonate)
  547.             {
  548.                 PenSize (mWidth + 2, mWidth + 2);
  549.                 PenPat (&qd.white);
  550.                 MoveTo (missiles[i].start.h-1, missiles[i].start.v-1);    //•    Erase the line.
  551.                 LineTo (newpixel.h - 1, newpixel.v - 1);
  552.  
  553.                 //•...turn off the missile.
  554.                 missiles[i].mode = msIdle;    
  555.                 nMissiles--;
  556.  
  557.                 if  (detonate) 
  558.                 {
  559.                     if  ((mFlag2 == 2) ||  ((mFlag2 == 1) &&  (MunafoRandom (25) > roundNumber)))
  560.                         AllocateFireballs (newpixel);                //•    Make a new fireball.
  561.  
  562.                     eDestroyed++;
  563.                     Score = Score + MPoints[missiles[i].kind];
  564.                     UpdateScore ();
  565.                 }
  566.                 else
  567.                     if  (cities[missiles[i].city]) 
  568.                     {
  569.                         AllocateFireballs (newpixel);
  570.                         cities[missiles[i].city] = false;
  571.                         citiesLeft--;
  572.                         
  573.                         if  (citiesLeft + bonusCities == 0) 
  574.                             gameOver = true;
  575.                     }
  576.             }
  577.         }
  578.     }
  579. }
  580.  
  581. //•    ------------------------------    CenterSomeText
  582.  
  583. void CenterSomeText (Str255 TheText, short posV)
  584. {
  585.     MoveTo ((fieldWidth - StringWidth (TheText)) >> 1, posV);
  586.     DrawString (TheText);
  587. }
  588.  
  589. //•    ------------------------------    ClearTheScreen
  590.  
  591. void ClearTheScreen ()
  592. {
  593. Rect    aRect;
  594.  
  595.     aRect.top = 0;
  596.     aRect.left = 0;
  597.     aRect.bottom = fieldHeight;
  598.     aRect.right = fieldWidth;
  599.     FillRect (&aRect, &qd.white);
  600. }
  601.  
  602. //•    ------------------------------    DrawACity
  603.  
  604. void DrawACity (short city)
  605. {
  606. Point        cityLocale;
  607. short    bOffset;
  608. Rect        aRect;
  609.  
  610.     qd.randSeed = 2;                                //•    Make each city look the same.
  611.     cityLocale.v = fieldHeight - cityHeight;
  612.     cityLocale.h =  (((city << 1) + 1) * fieldWidth) /  (numCities << 1);
  613.     bOffset = -  (cityWidth >> 1);
  614.     
  615.     while  (bOffset<  (cityWidth >> 1)) 
  616.     {
  617.         aRect.left = cityLocale.h + bOffset;
  618.         aRect.top = cityLocale.v - MunafoRandom (buildHeight);
  619.         aRect.bottom = cityLocale.v + 2;
  620.         aRect.right = aRect.left + buildWidth;
  621.         FillRect (&aRect, &(**cityPattern));
  622.         bOffset = bOffset + buildWidth;
  623.     }
  624. }
  625.  
  626. //•    ------------------------------    DrawOurStuff
  627.  
  628. void DrawOurStuff ()
  629. {
  630. short    i;
  631. Rect        aRect;
  632.  
  633.     ClearTheScreen ();
  634.  
  635.     for  (i = 0; i < numCities; i++)
  636.         if  (cities[i]) 
  637.             DrawACity (i);
  638.         
  639.     PenPat (&qd.black);
  640.     qd.randSeed = TickCount ();    //•    Randomize.
  641.  
  642.     DrawBottomLine ();
  643. }
  644.  
  645. //•    ------------------------------    NumStrMinMax
  646.  
  647. short
  648. NumStrMinMax (Str255 theString, short minimum, short MAXIMUM)
  649. {
  650. long    theNumber;
  651.  
  652.     StringToNum (theString, &theNumber);
  653.     
  654.     if  (theNumber < minimum) 
  655.         theNumber = minimum;
  656.         
  657.     if  (theNumber > MAXIMUM) 
  658.         theNumber = MAXIMUM;
  659.         
  660.     return  (theNumber);
  661. }
  662.  
  663. //•    ------------------------------    DoGameOptions
  664.  
  665. void DoGameOptions ()
  666. {
  667.     //•    Here are all the magic constants that go with that monster dialog box:
  668.     #define OK     1                //•    OK button.
  669.     #define GSpeed     5            //•    Game Speed text box.
  670.     #define sRound     7            //•    Start Round text box.
  671.     #define MPB    18                //•    mpBase text boxes.
  672.     #define MPE    24                //•    mpExtra text boxes.
  673.     #define MF1     8                //•    mFlag1 check box.
  674.     #define MF2    10                //•    mFlag2 radio buttons.
  675.     #define MEX    15                //•    mExists check boxes.
  676.     
  677.     GrafPtr        savePort;        //•    For saving the GrafPort and restoring later.
  678.     DialogPtr    dPtr;            //•    Pointer to my dialog box.
  679.     short        itemHit;        //•    Item that was just hit by the user.
  680.     short        theType;        //•    not used.
  681.     Handle        theHandle;        //•    Temp. handle.
  682.     Rect        theRect;        //•    not used.
  683.     Str255        theString;        //•    Temp. string.
  684.     short        theValue;        //•    Temp. integer value.
  685.     short        i;                //•    Loop Variable.
  686.     short        station;        //•    Current setting of radio buttons.
  687.  
  688.     dPtr = GetNewDialog (optionsDialog, nil,  (WindowPtr) -1L);
  689.  
  690.     GetDItem (dPtr, GSpeed, &theType, &theHandle, &theRect);            //•    Set up all the EditText boxes.
  691.     NumToString (gameSpeed, theString);
  692.     SetIText (theHandle, theString);
  693.  
  694.     GetDItem (dPtr, sRound, &theType, &theHandle, &theRect);
  695.     NumToString (startRound, theString);
  696.     SetIText (theHandle, theString);
  697.  
  698.     for (i = 0; i < 2; i++) 
  699.     {
  700.         GetDItem (dPtr, MPB + i, &theType, &theHandle, &theRect);        //•    Text for points each missile is worth.
  701.         NumToString (mpBase[i + 1], theString);
  702.         SetIText (theHandle, theString);
  703.  
  704.         GetDItem (dPtr, MPB + 3 + i, &theType, &theHandle, &theRect);    //•    Text for plus sign.
  705.         SetPString (theString, "+");
  706.         SetIText (theHandle, theString);
  707.  
  708.         GetDItem (dPtr, MPE + i, &theType, &theHandle, &theRect);        //•    Text for additional points each round.
  709.         NumToString (mpExtra[i + 1], theString);
  710.         SetIText (theHandle, theString);
  711.  
  712.         GetDItem (dPtr, MPE + 3 + i, &theType, &theHandle, &theRect);        //•    text : '* round.
  713.         SetPString (theString, "* round");
  714.         SetIText (theHandle, theString);
  715.  
  716.         GetDItem (dPtr, MEX + i, &theType, &theHandle, &theRect);        //•    Check boxes for types of missiles.
  717.         theValue = 0;
  718.         
  719.         if  (mExists[i + 1])
  720.             theValue = 1;
  721.             
  722.         SetCtlValue ((ControlHandle) theHandle, theValue);
  723.     }
  724.     
  725.     for (i = 0; i < 2; i++) 
  726.     {    //•    Program the radio buttons.
  727.         GetDItem (dPtr, MF2 + i, &theType, &theHandle, &theRect);
  728.         theValue = 0;
  729.         if  (mFlag2 == i) theValue = 1;
  730.         SetCtlValue ((ControlHandle) theHandle, theValue);
  731.     }
  732.     station = MF2 + mFlag2;
  733.  
  734.     GetDItem (dPtr, MF1, &theType, &theHandle, &theRect);            //•    Set check box for mFlag1.
  735.     theValue = 0;
  736.     if  (mFlag1) theValue = 1;
  737.     SetCtlValue ((ControlHandle) theHandle, theValue);
  738.  
  739.     SelIText (dPtr, sRound, 0, 1000);                            //•    Initial selection is startRound.
  740.  
  741.     do
  742.     {
  743.         ModalDialog (0L, &itemHit);                                //•    Let them hit an item...
  744.  
  745.         switch  (itemHit)
  746.         {
  747.             //•    Was it one of our radio buttons?
  748.             case 10:
  749.             case 11:
  750.             case 12:
  751.                 GetDItem (dPtr, station, &theType, &theHandle, &theRect);    //•    Get the old one, and turn it off.
  752.                 SetCtlValue ((ControlHandle) theHandle, 0);
  753.                 station = itemHit;
  754.     
  755.                 GetDItem (dPtr, station, &theType, &theHandle, &theRect);    //•    Turn this one on.
  756.                 SetCtlValue ((ControlHandle) theHandle, 1);
  757.                 
  758.                 break;
  759.  
  760.             case 18:
  761.             case 15:
  762.             case 16:
  763.             case 17:
  764.                 GetDItem (dPtr, itemHit, &theType, &theHandle, &theRect);
  765.                 theValue = ! GetCtlValue ((ControlHandle) theHandle);    //•    Find the value and invert it.
  766.                 SetCtlValue ((ControlHandle) theHandle, theValue);
  767.                 
  768.                 break;
  769.         }
  770.     } while  ((itemHit != 1) &&  (itemHit != 2));
  771.  
  772.     if  (itemHit == OK)    //•    Have to get all the new values now!
  773.     {
  774.         GetDItem (dPtr, GSpeed, &theType, &theHandle, &theRect);        //•    Set up all the EditText boxes.
  775.         GetIText (theHandle, theString);
  776.         gameSpeed = NumStrMinMax (theString, 1, 99);
  777.  
  778.         GetDItem (dPtr, sRound, &theType, &theHandle, &theRect);
  779.         GetIText (theHandle, theString);
  780.         startRound = NumStrMinMax (theString, 1, 99);
  781.  
  782.         for (i = 0; i < 2; i++) 
  783.         {
  784.             //•    Text for points each missile is worth.
  785.             GetDItem (dPtr, MPB + i, &theType, &theHandle, &theRect);    
  786.             GetIText (theHandle, theString);
  787.             mpBase[i + 1] = NumStrMinMax (theString, -1000, 1000);
  788.  
  789.             //•    Text for additional points each round.
  790.             GetDItem (dPtr, MPE + i, &theType, &theHandle, &theRect);    
  791.             GetIText (theHandle, theString);
  792.             mpExtra[i + 1] = NumStrMinMax (theString, -1000, 1000);
  793.  
  794.             //•    Check boxes for types of missiles.
  795.             GetDItem (dPtr, MEX + i, &theType, &theHandle, &theRect);    
  796.             if  (GetCtlValue ((ControlHandle) theHandle) == 0)
  797.                 mExists[i + 1] = false;
  798.             else
  799.                 mExists[i + 1] = true;
  800.         }
  801.  
  802.         for (i = 0; i < 2; i++) 
  803.         {    //•    radio buttons.
  804.             GetDItem (dPtr, MF2 + i, &theType, &theHandle, &theRect);
  805.             if  (GetCtlValue ((ControlHandle) theHandle) == 1)
  806.                 mFlag2 = i;
  807.         }
  808.  
  809.         GetDItem (dPtr, MF1, &theType, &theHandle, &theRect);    //•    mFlag1.
  810.         if  (GetCtlValue ((ControlHandle) theHandle) == 0)
  811.             mFlag1 = false;
  812.         else
  813.             mFlag1 = true;
  814.     }
  815.  
  816.     DisposDialog (dPtr);
  817.     GetPort (&savePort);        //•    save whatever port was current.
  818.     SetPort (myWindow);
  819.     InvalRect (&screenRect);        //•    force the entire screen, including frame, to be redrawn.
  820.     SetPort (savePort);
  821. }
  822.  
  823. //•    ------------------------------    DoCommand
  824.  
  825. void DoCommand (long whichMenu)
  826. {
  827. short        theMenu;
  828. short        theItem;
  829. Str255        daName;
  830.  
  831. MenuHandle    tempMenu;
  832.  
  833.     theMenu = HiWord (whichMenu);
  834.     theItem = LoWord (whichMenu);
  835.     tempMenu = GetMenu (theMenu);
  836.  
  837.     switch (theMenu)
  838.     {
  839.         case appleMenu:
  840.             switch (theItem)
  841.             {
  842.                 case iAbout:
  843.                     Alert (aboutAlert, nil);
  844.                     break;
  845.                     
  846.                 default:
  847.                     GetItem (GetMHandle (appleMenu), theItem, daName);
  848.                     OpenDeskAcc (daName);
  849.                     break;
  850.             }
  851.             break;
  852.             
  853.         case fileMenu:
  854.             switch  (theItem)
  855.             {
  856.                 case iQuit:
  857.                 {
  858.                     HUnlock ((Handle) crosshair);
  859.                     SetCursor (&qd.arrow);
  860.                     ExitToShell ();
  861.                 }
  862.             }
  863.             break;
  864.             
  865.         case gameMenu:
  866.             switch (theItem)
  867.             {
  868.                 case iPause: 
  869.                     pauseFlag = true;    //•    pause game.
  870.                     break;
  871.                 
  872.                 case iResume: 
  873.                     pauseFlag = false;    //•    resume game.
  874.                     break;
  875.                 
  876.                 case iOptions: 
  877.                     DoGameOptions ();
  878.                     break;
  879.                 
  880.                 case iNewGame: 
  881.                 {                    //•    New Game.
  882.                     gameOver = true;
  883.                     endDelay = 100;
  884.                     esFlag = false;
  885.                     pauseFlag = false;
  886.                 }
  887.                 break;
  888.  
  889.             }
  890.             break;
  891.     }
  892.     
  893.     HiliteMenu (0);
  894. }
  895.  
  896. //•    ------------------------------    CheckEvents
  897.  
  898. void CheckEvents ()
  899. {
  900.     Point        mousePoint;
  901.     short    mouseCode;
  902.     char        theChar;
  903.     short        i;
  904.     Rect        fbRect;        //•    Rectangle for drawing fireballs.
  905.     
  906.     crosshair2 = GetCursor (257);                        //•    Load the Crosshairs cursor that I use in the game.
  907.     HLockHi ((Handle) crosshair2);
  908.  
  909.     do
  910.     {
  911.         SystemTask ();
  912.  
  913.         GetMouse (&mousePoint);
  914.         LocalToGlobal (&mousePoint);
  915.         mouseCode = FindWindow (mousePoint, &whichWindow);
  916.  
  917.         //•    If my window is activated, set cursor:
  918.         if  (FrontWindow () == myWindow)  
  919.             if  ((whichWindow == myWindow)        //•    If it's above my window, 
  920.                 &&  (mouseCode != inMenuBar)        //•    but not the scroll bar, 
  921.                 &&  (! pauseFlag)                //•    the game is 'active', 
  922.                 &&  (FrontWindow () == myWindow)    //•    my window is in front, .
  923.                 &&  (yLeft > 0))                    //•    and the user has missiles left, then:.
  924.                 SetCursor (*crosshair);            //•    Set the Missile Command cursor.
  925.             else 
  926.                 SetCursor (*crosshair2);                //•    Otherwise, use an arrow.
  927.  
  928.         while  (GetNextEvent (everyEvent, &myEvent))
  929.             switch (myEvent.what)
  930.             {
  931.                 case mouseDown:
  932.                 {
  933.                     code = FindWindow (myEvent.where, &whichWindow);
  934.                     switch (code)
  935.                     {
  936.  
  937.                         case inMenuBar:
  938.                             DoCommand (MenuSelect (myEvent.where));
  939.                             break;
  940.                         
  941.                         case inSysWindow:
  942.                             SystemClick (&myEvent, whichWindow);
  943.                             break;
  944.                         
  945.                         case inDrag:
  946.                             DragWindow (whichWindow, myEvent.where, &qd.thePort->portRect);
  947.                             break;
  948.                         
  949.                         case inContent:
  950.                         {
  951.                             //•    Can't select myWindow - must close 
  952.                             //•    other windows.
  953.                             if  ((whichWindow != FrontWindow ())
  954.                                 &&  (whichWindow != myWindow))  
  955.                                 SelectWindow (whichWindow);
  956.                             else
  957.                                 //•    Can't make fireballs while paused.
  958.                                 //•    Make sure they have some missiles left.
  959.                                 //•    Game must be running.
  960.                                 if  ((! pauseFlag) &&  (FrontWindow () == myWindow) &&  (yLeft > 0))
  961.                                 {
  962.                                     GlobalToLocal (&myEvent.where);
  963.                                     
  964.                                     //•    If it's too low...
  965.                                     if  (myEvent.where.v > nukeHeight)
  966.                                         myEvent.where.v = nukeHeight;        //•    ...make it legal.
  967.                                     
  968.                                     //•    Put a fireball in the list.
  969.                                     AllocateFireballs (myEvent.where);
  970.  
  971.                                     //•    They have less missiles now...
  972.                                     yLeft = yLeft - 1;        
  973.  
  974.                                     //•    ...let them know.
  975.                                     UpdateScore ();
  976.                                 }
  977.                         }
  978.                         break;
  979.                     }
  980.                 }
  981.                 break;
  982.                 
  983.                 //•    No Autokey - don't want to repeat Option-N.
  984.                 case keyDown:  
  985.                     //•    If command key was held down.
  986.                     if  (myEvent.modifiers & cmdKey)
  987.                     {
  988.                         theChar = myEvent.message & charCodeMask;
  989.                         DoCommand (MenuKey (theChar));
  990.                     }
  991.                     break;
  992.                 
  993.                 case updateEvt:
  994.                 {
  995.                     SetPort (myWindow);
  996.                     BeginUpdate (myWindow);
  997.                     if  (playing) 
  998.                     {
  999.                         for (i = 0; i < numCities; i++)
  1000.                             if  (cities[i])
  1001.                             {
  1002.                                 DrawACity (i);
  1003.                             }
  1004.                             
  1005.                             //•    Randomize after drawing cities.
  1006.                             qd.randSeed = TickCount ();    
  1007.  
  1008.                             for (i = 0; i < maxMS; i++)
  1009.                                 if  (missiles[i].mode == msActive)
  1010.                                 {
  1011.                                     PenSize (mWidth, mWidth);
  1012.                                     PenPat (&qd.gray);
  1013.                                     MoveTo (missiles[i].start.h, missiles[i].start.v);
  1014.                                     LineTo (missiles[i].pos.h >> FP_SHIFT, missiles[i].pos.v >> FP_SHIFT);
  1015.                                 }
  1016.  
  1017.                             for (i = 0; i < maxFB; i++)
  1018.                                 if  (fbs[i].mode != fbIdle)
  1019.                                 {
  1020.                                     fbRect = fbs[i].bounds;
  1021.                                     InsetRect (&fbRect, 30 - 2 * fbs[i].size, 30 - 2 * fbs[i].size);
  1022.                                     PenMode (patCopy);
  1023.                                     FillOval (&fbRect, &qd.black);
  1024.                                 }
  1025.                     }
  1026.                     
  1027.                     DrawBottomLine ();
  1028.                     
  1029.                     EndUpdate (myWindow);
  1030.                 }
  1031.                 break;
  1032.             }
  1033.  
  1034.     //•    If another window has been selected don't do anything except 
  1035.     //•    process events until game window is re-selected.
  1036.     } while  (! (FrontWindow () == myWindow) && ! pauseFlag);        
  1037. }    //•    CheckEvents.
  1038.  
  1039. //•    ------------------------------    GameOverScreen
  1040.  
  1041. void GameOverScreen ()
  1042. {
  1043. Rect        aRect;
  1044. short    i;
  1045. short    GameOffset, OverOffset;
  1046. Point        Center;
  1047.  
  1048.     TextSize (72);
  1049.     TextMode (srcBic);
  1050.     PenMode (patOr);
  1051.     PenPat (&qd.black);
  1052.     PenSize (5, 5);
  1053.  
  1054.     GameOffset = StringWidth ("\pGAME") >> 1;
  1055.     OverOffset = StringWidth ("\pOVER") >> 1;
  1056.     Center.v = fieldHeight >> 1;
  1057.     Center.h = fieldWidth >> 1;
  1058.  
  1059.     SetRect (&aRect, Center.h, Center.v, Center.h, Center.v);
  1060.  
  1061.     for (i = 0; i < 30; i++) 
  1062.     {
  1063.         CheckEvents ();
  1064.  
  1065.         InsetRect (&aRect, -5, -5);
  1066.         FrameOval (&aRect);
  1067.         TextSize (72);
  1068.         TextMode (srcBic);
  1069.         CenterSomeText ("\pGAME", Center.v - 12);
  1070.         CenterSomeText ("\pOVER", Center.v + 60);
  1071.     }
  1072.  
  1073.     PenMode (patBic);
  1074.     for (i = 0; i < 30; i++) 
  1075.     {
  1076.         CheckEvents ();
  1077.  
  1078.         FrameOval (&aRect);
  1079.         InsetRect (&aRect, 5, 5);
  1080.     }
  1081.  
  1082. }
  1083.  
  1084. //•    ------------------------------    InitializeRound
  1085.  
  1086. void InitializeRound ()
  1087. {
  1088. short    i, rMissiles, yMissiles;
  1089.     
  1090.     endDelay = 0;
  1091.     playing = true;
  1092.     roundOver = FALSE;
  1093.  
  1094.     DrawOurStuff ();    //•    Redraw screen.
  1095.  
  1096.     for (i = 0; i < maxFB; i++)
  1097.         fbs[i].mode = fbIdle;
  1098.  
  1099.     for (i = 0; i < maxMS; i++)
  1100.         missiles[i].mode = msIdle;
  1101.  
  1102.     for (i = 0; i < 3; i++)
  1103.         MPoints[i] = mpBase[i] + mpExtra[i] * roundNumber;
  1104.  
  1105.     for (i = 0; i < numCities; i++)
  1106.         cities2[i] = cities[i];
  1107.  
  1108.     nMissiles = 0;
  1109.     MIRV_Rate = 0;
  1110.     MIRV_Height = fieldHeight >> 2;
  1111.     MIRV_Nasty = 30;
  1112.     msSpeed = 60;
  1113.  
  1114.     if  (roundNumber > 2) 
  1115.         MIRV_Rate = 10;
  1116.  
  1117.     if  (roundNumber > 4) 
  1118.         msSpeed = 80;
  1119.  
  1120.     if  (roundNumber > 6) 
  1121.         MIRV_Rate = 20;
  1122.  
  1123.     if  (roundNumber > 8) 
  1124.         MIRV_Nasty = 50;
  1125.  
  1126.     if  (roundNumber > 10) 
  1127.         MIRV_Height = fieldHeight / 3;
  1128.  
  1129.     if  (roundNumber > 12) 
  1130.         msSpeed = 90;
  1131.  
  1132.     if  (roundNumber > 14) 
  1133.         MIRV_Rate = 30;
  1134.  
  1135.     if  (roundNumber > 19) 
  1136.         msSpeed = 100;
  1137.  
  1138.     msRate = 5 + roundNumber;
  1139.     rMissiles = (roundNumber * roundNumber) / 6 + roundNumber + 6;    //•    Compute # of enemy missiles.
  1140.     yMissiles = rMissiles + roundNumber;                        //•    Adjust yMissiles accordingly.
  1141.     eLeft = rMissiles;
  1142.     yLeft = yMissiles;
  1143.     roundNumber = roundNumber + 1;
  1144.     
  1145.     if  ((roundNumber % 5) == 0) 
  1146.         bonusCities = bonusCities + 1;
  1147.  
  1148.     DrawBottomLine ();
  1149.     FlushEvents (everyEvent, 0);    //•    Ignore unprocessed events from previous round.
  1150. }
  1151.  
  1152. //•    ------------------------------    EndRoundBonus
  1153.  
  1154. void EndRoundBonus ()
  1155. {
  1156. short    i, points;
  1157. Str255    aString, s;
  1158. char        tempString[256];
  1159.     
  1160.     ClearTheScreen ();
  1161.     DrawBottomLine ();
  1162.  
  1163.     TextSize (24);
  1164.     TextMode (srcCopy);
  1165.  
  1166.     sprintf (tempString, "End of round %d", roundNumber);
  1167.     SetPString (aString, tempString);
  1168.  
  1169.     if  (citiesLeft > 0)                        //•    give bonus points for cities.
  1170.     {
  1171.         CenterSomeText (aString, 100);
  1172.         CenterSomeText ("\pBonus:", 130);
  1173.         points = 0;
  1174.  
  1175.         for (i = 0; i < numCities; i++)
  1176.             if  ((cities[i] && !doneFlag)) 
  1177.             {
  1178.                 lastTick = TickCount ();
  1179.                 DrawACity (i);
  1180.                 points = points + roundNumber * 20;
  1181.                 Score = Score + roundNumber * 20;
  1182.                 TextSize (24);
  1183.                 NumToString (points, s);
  1184.                 CenterSomeText (s, 160);
  1185.                 UpdateScore ();
  1186.  
  1187.                 do
  1188.                 {
  1189.                     CheckEvents ();
  1190.                 } while  (! (TickCount () >= lastTick + 30) || doneFlag);
  1191.             }
  1192.     }
  1193.     
  1194.     if  ((bonusCities > 0) &&  (citiesLeft < 6))        //•    Give a bonus city.
  1195.     {
  1196.         lastTick = TickCount ();
  1197.         TextSize (24);
  1198.         CenterSomeText ("\p* Bonus City *", 190);
  1199.         citiesLeft = citiesLeft + 1;
  1200.         bonusCities = bonusCities - 1;
  1201.  
  1202.         do
  1203.         {
  1204.             i = MunafoRandom (6);
  1205.         } while  (! (! cities[i]));
  1206.         
  1207.         cities[i] = true;
  1208.         
  1209.         do
  1210.         {
  1211.             CheckEvents ();
  1212.         } while  (! (TickCount () >= lastTick + 60) || doneFlag);
  1213.     }
  1214. }
  1215.  
  1216.  
  1217. //•    ------------------------------    PlayMacMissile
  1218.  
  1219. void PlayMacMissile ()
  1220. {
  1221. short    i;
  1222. Str255    s;
  1223. Point        msPoint;
  1224. short    msCity, msKind;
  1225. short    rMissiles;                //•    "round missiles" - number to set eLeft to each round.
  1226. short    yMissiles;                //•    "your Missiles" - similar to rMissiles.
  1227. Str255    aString;
  1228. short    points;
  1229.  
  1230.     roundNumber = startRound;    //•    Start out at this round.
  1231.     Score = 0;
  1232.     eDestroyed = 0;
  1233.  
  1234.     for (i = 0; i < numCities; i++)
  1235.         cities[i] = true;
  1236.  
  1237.     citiesLeft = numCities;
  1238.     bonusCities = 0;
  1239.  
  1240.     nukeHeight = fieldHeight - cityHeight -  (buildHeight >> 1) -  (fbRad * fbRadRate);
  1241.     endv = fieldHeight - cityHeight -  (buildHeight >> 1);
  1242.  
  1243.     gameOver = false;
  1244.     esFlag = true;
  1245.     lastTick = TickCount ();
  1246.  
  1247.     do            //•    Repeat loop for playing rounds.
  1248.     {
  1249.         InitializeRound ();
  1250.  
  1251.         do        //•    Repeat loop for animating objects in game.
  1252.         {
  1253.             CheckEvents ();
  1254.  
  1255.             if  (TickCount () >= lastTick + gameSpeed)  //•    If enough time has elapsed since the                                                                            last update, update objects on screen. 
  1256.             {
  1257.                 lastTick = TickCount ();
  1258.                 
  1259.                 if  ((eLeft < 1) &&  (nMissiles < 1))
  1260.                     roundOver = true;
  1261.  
  1262.                 if  (roundOver || gameOver)
  1263.                     endDelay = endDelay + 1;
  1264.                 else
  1265.                     if  ((MunafoRandom (100) < msRate) &&  (eLeft > 0)) 
  1266.                     {    //•    Launch an enemy missile every now and then.
  1267.                         eLeft = eLeft - 1;
  1268.                         msPoint.v = 0;
  1269.                         msPoint.h = MunafoRandom (fieldWidth - 4);
  1270.  
  1271.                         do
  1272.                         {
  1273.                             msCity = MunafoRandom (numCities);        //•    Pick a city.
  1274.                         } while  (! (((MunafoRandom (3) == 1) && mFlag1) || cities2[msCity]));    //•    Try again for most missiles if city was destroyed.
  1275.  
  1276.                         msKind = 0;
  1277.                         if  (mExists[msNormal])
  1278.                             msKind = msNormal;
  1279.                             
  1280.                         if  ((MunafoRandom (100) <= MIRV_Rate) &&  mExists[msMIRV])
  1281.                             msKind = msMIRV;
  1282.                             
  1283.                         if  (msKind == 0) 
  1284.                             msKind = msNormal;
  1285.  
  1286.                         AllocateMissiles (msPoint, msCity, msKind);
  1287.                     }
  1288.                     
  1289.                     AdvanceFireballs ();        //•    Advance state of fireballs.
  1290.                     AdvanMS ();        //•    Advance position of missiles.
  1291.                 }
  1292.             } while  (! (((gameOver || roundOver) &&   (endDelay > 30)) || doneFlag));
  1293.             
  1294.             playing = false;
  1295.             
  1296.             if  (esFlag &&  (citiesLeft + bonusCities > 0) && !doneFlag) 
  1297.                 EndRoundBonus ();
  1298.  
  1299.         } while  (! (gameOver || doneFlag));
  1300.  
  1301.         if  (Score > highScore)
  1302.             highScore = Score;
  1303.  
  1304.         if  (esFlag)
  1305.             GameOverScreen ();
  1306. }
  1307.  
  1308. //•    ------------------------------    main
  1309.  
  1310. void main ()
  1311. {
  1312.     SetupEverything ();
  1313.  
  1314.     do
  1315.     {
  1316.         PlayMacMissile ();
  1317.     } while  (!doneFlag);
  1318. }
  1319.  
  1320. //•    ------------------------------    SetPString
  1321.  
  1322. void SetPString (Str255 thePString, char *theCString)
  1323. {
  1324.     CtoPstr (theCString);
  1325.     BlockMove (theCString, thePString, theCString[0] + 1);
  1326. }